/**
 * 
 */
package prj3;

/**
 * Grid cell on a spherical grid. This cell is the basic cell
 * on the spherical grid representing the earth
 * @author romain
 *
 */
import java.lang.Math;

import prj3.exceptions.EmptyListException;

public class SphericalCell implements ICell, IHistoryValue {

	static final float DEFAULT_VALUE = 15;
	
	/**
	 * Construct a spherical cell for the grid and with the 
	 * Coordinate coord. The value of the cell will be DEFAULT_VALUE
	 * coord is the coordinate of the south-western corner of this cell
	 * @param grid on which this cell resides
	 * @param coord of this cell
	 */
	public SphericalCell(SphericalGrid grid, SphericalCoordinate coord) {
		this(grid, coord, DEFAULT_VALUE);
	}
	
	/**
	 * Construct a spherical cell for the grid and with the 
	 * Coordianate coord. The value of the cell will be set to _value
	 * coord is the coordinate of the south-western corner of this cell
	 * @param grid
	 * @param coord
	 * @param _value
	 */
	public SphericalCell(SphericalGrid grid, SphericalCoordinate coord, float _value) {
		float phi = coord.getPhi();
		float theta = coord.getTheta();
		
		float t_radius = coord.getRadius();
		float t_diffphi = grid.getStepPhi();
		float t_difftheta = grid.getStepTheta();
		/* Calculate the sides */
		// Top side
		//if(theta > t_difftheta)
			calcSides[ICoordinate.DIR_TOP] = t_radius*(float)Math.sin(theta - t_difftheta)*t_diffphi;
	//	else
	//		calcSides[ICoordinate.DIR_TOP] = 0;
		
		// Bottom
		calcSides[ICoordinate.DIR_BOTTOM] = t_radius*(float)Math.sin(theta)*t_diffphi;
		
		// Both sides are the same
		calcSides[ICoordinate.DIR_RIGHT] = calcSides[ICoordinate.DIR_LEFT] = 
			(float)Math.sqrt(Math.pow(Math.abs(calcSides[ICoordinate.DIR_TOP] - calcSides[ICoordinate.DIR_BOTTOM])/2, 2) + 
					Math.pow(t_radius*Math.sin(theta)*t_difftheta, 2));
		
		calcArea = (float)((calcSides[ICoordinate.DIR_TOP] + calcSides[ICoordinate.DIR_BOTTOM])/2 * t_radius*(float)Math.sin(theta)*t_difftheta);
		
		myGrid = grid;
		value = oldValue = _value;
		this.coord = coord;
	}
	
	// TODO Add deep copy constructor for spherical Cell
	// Should possibly store 
	// Or possibly extend SphericalCell to BufferedSphericalCell
	// add buffer for temperature values
	// In EarthAlgorithm, set newly computed value aside.
	// Commit at end.  Block if buffer full when committing.
	
	
	
	/* Private variables */
	protected float[] calcSides = new float[4]; // Using DIR_TOP, etc.
	protected float calcArea;
	protected float value;
	protected float oldValue;
	protected SphericalGrid myGrid;
	protected boolean mutable;
	protected SphericalCoordinate coord;
	
	/* Inherited methods */
	/* (non-Javadoc)
	 * @see prj3.ICell#getArea()
	 */
	public float getArea() {
		return calcArea;
	}

	/* (non-Javadoc)
	 * @see prj3.ICell#getSideLength(int)
	 */
	public float getSideLength(int direction) {
		if(direction >= 0 && direction < 4)
			return calcSides[direction];
		return 0;
	}

	/* (non-Javadoc)
	 * @see prj3.prj2.ICell#getTotalSideLength()
	 */
	public float getTotalSideLength() {
		return (calcSides[0] + calcSides[1] + calcSides[2] + calcSides[3]);
	}

	/* (non-Javadoc)
	 * @see prj3.prj2.ICell#isMutable()
	 */
	public boolean isMutable() {
		return mutable;
	}

	/* (non-Javadoc)
	 * @see prj3.prj2.ICell#setMutable(boolean)
	 */
	public void setMutable(boolean mutable) {
		this.mutable = mutable;	
	}

	/* (non-Javadoc)
	 * @see prj3.prj2.ICell#getValue()
	 */
	public float getValue() {
		return value;
	}
    
    /* (non-Javadoc)
     * @see prj3.prj2.ICell#getValue()
     */
    public float takeValue() throws EmptyListException {
        return value;
    }

	/* (non-Javadoc)
	 * @see prj3.prj2.ICell#setValue(float)
	 */
	public void setValue(float value) {
		if(mutable)
			this.value = value;
		else
			throw new AssertionError(!mutable);
		
	}

	
	/* (non-Javadoc)
	 * @see prj3.prj2.ICell#getCoordinate()
	 */
	public ICoordinate getCoordinate() {
		return coord;
	}

	/* (non-Javadoc)
	 * @see prj3.prj2.IHistoryValue#getHistoryValue()
	 */
	public float getHistoryValue() {
		return oldValue;
	}

	/* (non-Javadoc)
	 * @see prj3.prj2.IHistoryValue#setHistoryValue(float)
	 */
	public void setHistoryValue(float value) {
		oldValue = value;
		
	}

	/* (non-Javadoc)
	 * @see prj3.prj2.IHistoryValue#switchValues()
	 */
	public boolean switchValues() {
		float t = oldValue;
		oldValue = value;
		value = t;
        return true;
		
	}	
}
